///
/// Random Number Generator (RNG) Class
/// This class generates uniform distributed samples and is the core element to generate other probability 
/// distributions, continous and discrete.
/// 
/// See LICENSE.TXT for licensing details
///

using System;
using System.Collections.Generic;
using System.Text;


namespace Dsp
{
    /// <summary>
    /// Random Number Generator (RNG) Class. Implements various classic algorihms for uniform random number 
    /// generation selectable with the Type property. The type "Platform" uses System.Random (.NET RNG)
    /// </summary>
    public class RNG
    {
        // Kobayashi values por LCG (Linear Congruence Generator)
        const uint LCG_m = 2147483648;
        const uint LCG_a = 0314159269;
        const uint LCG_c = 0453806245;

        public enum RNGType 
        {
            Platform,
            LCG,
            MT19937
        }

        private RNGType rngtype;
        private string  rngtypename;
        private uint    state;
        private uint    count;

        private delegate uint RngNextProc();
        private RngNextProc RngNext;

       
        public RNG()
        {
            count = 0;
            state = 0;

            rngtype     = RNGType.LCG;
            rngtypename = "LCG";

            RngNext = RngLCG;

        }


        /// <summary>
        /// The most simple RNG: The Linear Congruential Generator (LGC) 
        /// </summary>
        /// <returns>UInt32 sample uniformly distributed</returns>
        private uint RngLCG()
        {
            state = (state * LCG_a + LCG_c) % LCG_m;
            count++;

            return state;
        }

        /// <summary>
        /// Sets the initial seed for RNG and clear the counter of samples generated (count)
        /// </summary>
        /// <param name="pseed">Initial seed</param>
        public void Init(UInt32 seed)
        { state = seed; }


        public RNGType Type
        {
            get { return rngtype;  }
            set { rngtype = value; }
        }
        
        public string TypeName
        { get { return rngtypename; } }


        /// <summary>
        /// This property lets to access to the internal state of the RNG. In simulations, often is necesary
        /// to obtain the internal state of the RNGs to save it in a file and restore it later.
        /// </summary>
        public uint State 
        {
            get { return state;  }
            set { state = value; }
        }

        /// <summary>
        // /Number of samples generated by now
        /// </summary>
        public uint Count
        { get { return count; } }

        /// <summary>
        /// Get the next random sample in the interval [0, 1), 1 is not included
        /// </summary>        
        public double Next()
        {
            double s;

            s = (double) RngNext() / LCG_m;

            return s;
        }

        /// <summary>
        /// Get the next random sample in the interval (0, 1), neither 0 nor is included. If the value 
        /// returned by the RNG is 0, it obtains another sample until it is non-zero.
        /// </summary>        
        public double NextPos()
        {
            double s;

            while ((s = Next()) == 0.0) ;

            return s;
        }

        /// <summary>
        /// Get the next random sample in the interval [0, n-1], the sample returned is 32-bit unsigned 
        /// integer
        /// </summary>        
        public uint NextInt()
        {
            return RngNext();
        }
    }
}
